package com.green.common.fusionchart.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.green.common.fusionchart.Apply;
import com.green.common.fusionchart.Categories;
import com.green.common.fusionchart.Category;
import com.green.common.fusionchart.Chart;
import com.green.common.fusionchart.DataSet;
import com.green.common.fusionchart.FontStyle;
import com.green.common.fusionchart.Line;
import com.green.common.fusionchart.Set;
import com.green.common.fusionchart.Style;
import com.green.common.fusionchart.enums.ToObjectEnum;

public class XmlHelper {

	public static int scale = 2;
	
	public static Element getChartElement(Object o) {
		Element chart = getElement("chart");
		chart = setAttributeForElement(chart, o);
		// Assert.notNull(chart, "属性设置错误");

		return chart;
	}

	public static Element getElement(String elementName) {
		Element element = DocumentHelper.createElement(elementName);

		return element;
	}

	public static Element setAttributeForElement(Element element, Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
		try {
			Object selfValue = null;
			for (Field field : fields) {
				// 设置属性能强制访问
				if (Modifier.isPrivate(field.getModifiers())) {
					field.setAccessible(true);
					selfValue = field.get(o);
					if (null != selfValue) {
						adjustValueType(element, field, o, selfValue);
					}
				}
			}
			// 找到不为Object的父类
			for (Class<?> superClass = o.getClass().getSuperclass(); superClass != Object.class; superClass = superClass
					.getSuperclass()) {
				// 将父类的属性也加入到元素中
				Field[] parents = superClass.getDeclaredFields();
				Object value = null;
				for (Field parent : parents) {
					// 先让父类的属性都能强制访问
					if (Modifier.isPrivate(parent.getModifiers())) {
						parent.setAccessible(true);
						value = parent.get(o);
						if (null != value) {
							adjustValueType(element, parent, o, value);
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

		return element;
	}

	public static Element adjustValueType(Element element, Field field,
			Object o, Object value) throws IllegalArgumentException,
			IllegalAccessException {
		if (value instanceof Boolean) {
			setBooleanAttribute(element, field, o);
		} else if (value instanceof String[]) {
			setStringArrayAttribute(element, field, o);
		} else if (value instanceof Integer) {
			setIntegerAttribute(element, field, o);
		} else if (value instanceof Enum) {
			setEnumAttribute(element, field, o);
		} else if (value instanceof BigDecimal) {
			setBigDecimalAttribute(element, field, o);
		} else if (value instanceof DataSet) {
			setDataSet(element, field, o);
		} else if (value instanceof Categories) {
			setCategories(element, field, o);
		}else if (value instanceof List) {
			// 得到泛型参数类型
			Type type = field.getGenericType();
			if (type instanceof ParameterizedType) {
				ParameterizedType pt = (ParameterizedType) field
						.getGenericType();
				Class ptClass = (Class) pt.getActualTypeArguments()[0];
				if (ptClass == Style.class) {
					setStyles(element, (List<Style>) value);
				} else if (ptClass == Apply.class) {
					setApplys(element, (List<Apply>) value);
				} else if (ptClass == Set.class) {
					setSets(element, (List<Set>) value);
				} else if (ptClass == Category.class) {
					setCategory(element, (List<Category>) value);
				} else if (ptClass == DataSet.class) {
					setMSDataSet(element, (List<DataSet>) value);
				}else if(ptClass == Line.class){
					setLineList(element,(List<Line>) value);
				}
			}
		} else
			element.addAttribute(field.getName(), (String) field.get(o));

		return element;
	}

	public static Element setBigDecimalAttribute(Element element, Field field,
			Object o) throws IllegalArgumentException, IllegalAccessException {
		BigDecimal value = (BigDecimal) field.get(o);
		value = value.setScale(2, BigDecimal.ROUND_HALF_EVEN);
		element.addAttribute(field.getName(), value.toString());
		return element;
	}

	public static Element setEnumAttribute(Element element, Field field,
			Object o) throws IllegalArgumentException, IllegalAccessException {
		Enum value = (Enum) field.get(o);
		element.addAttribute(field.getName(), value.name());
		return element;
	}

	public static Element setIntegerAttribute(Element element, Field field,
			Object o) throws IllegalArgumentException, IllegalAccessException {
		int value = (Integer) field.get(o);
		element.addAttribute(field.getName(), String.valueOf(value));
		return element;
	}

	public static Element setBooleanAttribute(Element element, Field field,
			Object o) throws IllegalArgumentException, IllegalAccessException {
		Boolean value = (Boolean) field.get(o);
		if ((Boolean) value)
			element.addAttribute(field.getName(), "1");
		else
			element.addAttribute(field.getName(), "0");
		return element;
	}

	public static Element setStringArrayAttribute(Element element, Field field,
			Object o) throws IllegalArgumentException, IllegalAccessException {
		String[] values = (String[]) field.get(o);
		String spellValue = "";
		String value = "";
		for (int i = 0; i < values.length; i++) {
			value = values[i];
			if (i != values.length - 1)
				spellValue += value + ",";
			else
				spellValue += value;
		}
		element.addAttribute(field.getName(), spellValue);
		return element;
	}

	public static Element setCategories(Element element, Field field, Object o)
			throws IllegalArgumentException, IllegalAccessException {
		Categories value = (Categories) field.get(o);
		Element categories = element.addElement("categories");
		setAttributeForElement(categories, value);
		return element;
	}

	public static Element setDataSet(Element element, Field field, Object o)
			throws IllegalArgumentException, IllegalAccessException {
		DataSet value = (DataSet) field.get(o);

		Element dataSet = element.addElement("dataset");

		setAttributeForElement(dataSet, value);
		return element;
	}

	public static Element setCategory(Element element, List<Category> list) {
		if (list == null || list.size() == 0)
			return element;
		Element category = null;
		for (Category c : list) {
			category = element.addElement("category");
			setAttributeForElement(category, c);
		}

		return element;
	}

	public static Element setLineList(Element element, List<Line> list) {
		if (list == null || list.size() == 0)
			return element;
		Element trend= element.addElement("trendlines");
		Element line = null;
		for (Line ld : list) {
			line = trend.addElement("line");
			setAttributeForElement(line,ld);
		}

		return element;
	}
	
	
	public static Element setStyles(Element element, List<Style> list) {
		// 这里都没做判断的 可以加上名字属性没设置就不能增加的判断
		// 现在所有节点我都没加判断 以后有时间再完善
		if (list == null || list.size() == 0) {
			return element;
		}
		Element styles = element.addElement("styles");
		Element style = null;
		for (Style s : list) {
			style = styles.addElement("style");
			setAttributeForElement(style, s);
		}

		return element;
	}

	public static Element setApplys(Element element, List<Apply> list) {
		if (list == null || list.size() == 0) {
			return element;
		}
		Element application = element.addElement("application");
		Element apply = null;
		for (Apply a : list) {
			apply = application.addElement("apply");
			setAttributeForElement(apply, a);
		}

		return element;
	}

	public static Element setSets(Element element, List<Set> list) {
		if (list == null || list.size() == 0)
			return element;
		Element set = null;
		for (Set s : list) {
			set = element.addElement("set");
			setAttributeForElement(set, s);
		}
		return element;
	}

	public static Element setMSDataSet(Element element, List<DataSet> list) {
		if (list == null || list.size() == 0)
			return element;
		Element dataSet = null;
		for (DataSet ds : list) {
			dataSet = element.addElement("dataset");
			setAttributeForElement(dataSet, ds);
		}

		return element;
	}
	
	/**
	 * 验证报表数据和名字是否匹配
	 * @param chart
	 * @throws Exception
	 */
	public static void validateCount(Chart chart) throws Exception {
		Categories categories = chart.getCategories();
		List<DataSet> dataSet = chart.getDataSets();
		if (categories != null && dataSet != null) {
			int categorys = 0;
			int dataSets = 0;

			if (categories.getCategories().size() == 0)
				throw new Exception("X轴坐标名字不能为空");
			else
				categorys = categories.getCategories().size();
			
			if(dataSet.size() == 0)
				throw new Exception("Y轴值不能为空");
			else{
				for(DataSet set : dataSet){
					if(set.getSets() == null)
						throw new Exception("Y轴值不能为空");
					else{
						dataSets = set.getSets().size();
						if(categorys != dataSets)
							throw new Exception("名字与值的数量不对");
					}
				}
			}
			
		}

	}

}
